#include <amxmodx>
#include <amxmisc>
#include <regex>

// - From nvault.h -
#define VAULT_MAGIC   0x6E564C54     //nVLT
#define VAULT_VERSION 0x0200         //second version

/*  
    nVault File Format
 
    VAULT_MAGIC       (uint32)
    VAULT_VERSION     (uint16)
    ENTRIES           (int32)
    [
        TimeStamp     (int32)
        KeyLen        (uint8)
        ValLen        (uint16)
        KeyData       ([])
        ValData       ([])
    ]                                 
*/

new const Version[] = "0.1";

const MaxKeyLen  = 255;     //Max 255
const MaxValLen  = 512;     //Max 65535
const DataBuffer = 128;     //Make this the greater of (MaxKeyLen / 4) or (MaxValLen / 4)
new const g_CodTable[] = "codmod";
new Regex:regex;

public plugin_init() 
{
	register_plugin( "nVault File Reader" , Version , "bugsy" );
	
	register_clcmd("amc_readsql","Read_Sql_File",ADMIN_IMMUNITY);
}


public Read_Sql_File(id, level,cid){
	if(!cmd_access(id,level,cid,1))
		return PLUGIN_HANDLED;
	ReadVault("CodMod");
	client_print(id, print_console, "Wykonano");
	return PLUGIN_HANDLED;
}
public ReadVault( const szVault[] )
{
	new ret;
	new errorMsg[256];
	new iVaultEntries;
	regex = regex_compile("(.*)-(\d*)-cod$",ret, errorMsg, 255);
	if(regex){
		new szFile[ 64 ] , iFile;
		new iVaultMagic , iVaultVersion;
		new iKeyLen , iValLen , iTimeStamp;
		new szKey[ MaxKeyLen + 1 ] , szVal[ MaxValLen + 1 ] , RawData[ DataBuffer ];
		
		formatex( szFile[ get_datadir( szFile , charsmax( szFile ) ) ] , charsmax( szFile ) , "/vault/%s.vault" , szVault );
		
		iFile = fopen( szFile , "rb" );
		
		if ( !iFile )
			return 0;
	    
		// Vault Magic
		fread_raw( iFile , RawData , 1 , BLOCK_INT );
		iVaultMagic = RawData[ 0 ];
		
		if ( iVaultMagic != VAULT_MAGIC )
		set_fail_state( "Error reading nVault: Vault Magic" );
		
		// Vault Version
		fread_raw( iFile , RawData , 1 , BLOCK_SHORT );
		iVaultVersion = RawData[ 0 ] & 0xFFFF;
		
		if ( iVaultVersion != VAULT_VERSION )
			set_fail_state( "Error reading nVault: Vault Version" );
		
		// Vault Entries
		fread_raw( iFile , RawData , 1 , BLOCK_INT );
		iVaultEntries = RawData[ 0 ];
		
		server_print( "nVault | Magic=%d Version=%d Entries=%d" , iVaultMagic , iVaultVersion , iVaultEntries );
		server_print( " " );

		for ( new iEntry = 0 ; iEntry < iVaultEntries ; iEntry++ )
		{
			// TimeStamp
			fread_raw( iFile , RawData , 1 , BLOCK_INT );
			iTimeStamp = RawData[ 0 ];
			
			// Key Length
			fread_raw( iFile , RawData , 1 , BLOCK_BYTE );
			iKeyLen = RawData[ 0 ] & 0xFF;
			
			// Val Length
			fread_raw( iFile , RawData , 1 , BLOCK_SHORT );
			iValLen = RawData[ 0 ] & 0xFFFF;
			
			// Key Data
			fread_raw( iFile , RawData , iKeyLen , BLOCK_CHAR );
			ReadString( szKey , iKeyLen , charsmax( szKey ) , RawData );
			
			// Val Data
			fread_raw( iFile , RawData , iValLen , BLOCK_CHAR );
			ReadString( szVal , iValLen , charsmax( szVal ) , RawData );
			
			server_print( "Entry=%d KeyLen=%d ValLen=%d TimeStamp=%d" , iEntry , iKeyLen , iValLen , iTimeStamp );
			server_print( "Key=^"%s^"" , szKey );
			server_print( "Val=^"%s^"" , szVal );
			server_print( " " );
			ZapiszDoPliku(szVal, szKey);
		}
		fclose( iFile );
	}
	regex_free(regex);
	return iVaultEntries;
}


public ZapiszDoPliku(vaultdata[], vaultkey[])
{
	new ret;
	
	new plik[128];
	get_datadir(plik, 127);
	format(plik, 127, "%s\cod.sql",plik);
	log_amx("ZapiszDoPliku, %s",plik);
	if(regex_match_c(vaultkey, regex, ret))
	{
		log_amx("regexmatch");
		new gracz[64];
		new klasaStr[4];
		new klasa_gracza;
		regex_substr(regex, 1, gracz, 63);
		regex_substr(regex, 2, klasaStr, 3);
		klasa_gracza = str_to_num(klasaStr);
		
		replace_all(vaultdata, 255, "#", " ");
	 
		new doswiadczeniegracza[32], poziomgracza[32], inteligencjagracza[32], silagracza[32], zrecznoscgracza[32], zwinnoscgracza[32];
	 
		parse(vaultdata, doswiadczeniegracza, 31, poziomgracza, 31, inteligencjagracza, 31, silagracza, 31, zrecznoscgracza, 31, zwinnoscgracza, 31);
	 
		new doswiadczenie_gracza = str_to_num(doswiadczeniegracza);
		new poziom_gracza = str_to_num(poziomgracza)>0?str_to_num(poziomgracza):1;
		new inteligencja_gracza = str_to_num(inteligencjagracza);
		new zdrowie_gracza = str_to_num(silagracza);
		new wytrzymalosc_gracza = str_to_num(zrecznoscgracza);
		new kondycja_gracza = str_to_num(zwinnoscgracza);

		new query[512];

		replace_all(gracz, 63, "'","''");
		format(query, 511,"INSERT INTO `%s` \
(`gracz`,`klasa`,`poziom`,\
`doswiadczenie`,`zdrowie`,`inteligencja`,\
`kondycja`,`wytrzymalosc`) VALUE ('%s',%d,%d,%d,%d,%d,%d,%d\
) on duplicate key update \
`poziom`=%d,`doswiadczenie`=%d,`zdrowie`=%d,\
`inteligencja`=%d,`kondycja`=%d,`wytrzymalosc`=%d;",g_CodTable,gracz,klasa_gracza,poziom_gracza,
doswiadczenie_gracza,zdrowie_gracza,inteligencja_gracza,kondycja_gracza,wytrzymalosc_gracza,
poziom_gracza,doswiadczenie_gracza,zdrowie_gracza,inteligencja_gracza,kondycja_gracza,wytrzymalosc_gracza);
		write_file(plik, query);
	}
}

ReadString( szDestString[] , iLen , iMaxLen , SourceData[] )
{
    new iStrPos = -1;
    new iRawPos = 0;
    
    while ( ( ++iStrPos < iLen ) && ( iStrPos < iMaxLen ) && ( iRawPos < DataBuffer ) )
    {
        szDestString[ iStrPos ] = ( SourceData[ iRawPos ] >> ( ( iStrPos % 4 ) * 8 ) ) & 0xFF;
        
        if ( iStrPos && ( ( iStrPos % 4 ) == 3 ) )
            iRawPos++
    }
    
    szDestString[ iStrPos ] = EOS;
} 
